//import java.awt.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class Polygon extends PhysicsObject {
	public static int MAX_GENERATIONS = 3;
	public static int MAX_SIDES = 7; 
	public static Color3f ASTEROID_COLOR1 = new Color3f(0.5f,0.5f,0.5f);
	public static Color3f ASTEROID_COLOR2 = new Color3f(0.55f,0.5f,0.5f); //.6, .5, .5
	public static Color3f ASTEROID_COLOR3 = new Color3f(0.25f,0.25f,0.25f); //.25, .25, .25
	public static Color3f ASTEROID_COLOR4 = new Color3f(0.15f,0.15f,0.2f); // .25, .25, .2
	
	private static float DEFAULT_MASS = 10f;
	private static float DEFAULT_RATIO = 0.2f;
	
	public float max_radius;
	
	public Color3f color;
	
	private float[] vertices;
	
	public float width;
	private float ratio;
	private Vector2f[] vertexCache;
	private Vector2f[] normalCache;
	
	private int /* talkin bout */ my_generation;
	
	/** type: 1-asteroid, 2-ship, 3-enemy */
	public Polygon(int type, int sides, float mass, float positionX, float positionY, 
			float velocityX, float velocityY, float orientation, 
			float angularVelocity, float extwidth, float ratio, Color3f color) {
		super(mass, positionX, positionY, velocityX, velocityY, orientation, angularVelocity);
		
		if (extwidth*ratio <= 0  || sides < 3)
			throw new IllegalArgumentException();
		
		this.ratio = ratio;
		
		//calculate vertices positions of polygon with 
		//	given number of sides centered around origin
		vertices = new float[sides*2];
		float r = extwidth*ratio;//width/2;
		float max_scale = 0;
		double pi = Math.PI;
		for (int i = 0; i < sides*2; i+=2) {
			float scale = 0.5f + (float)Math.random() /2f;
			if (scale < 0.5f)
				scale = 0.5f;	
			if (scale > max_scale)
				max_scale = scale;
			vertices[i] = (float) (scale * r * Math.cos(pi*i/sides));
			vertices[i+1] = (float) (scale * r * Math.sin(pi*i/sides));
			
			if (type == 2) {
				scale = 1;
				vertices[i] = (float) (1.5* scale * r * Math.cos(pi*i/sides));
				vertices[i+1] = (float) (scale * r * Math.sin(pi*i/sides));
			}
			
			if (type == 3) {
				scale = 1;
				if (i == 2 || i == 8)
					scale = 2;
				vertices[i] = (float) (scale * r * Math.cos(pi*i/sides));
				vertices[i+1] = (float) (scale * r * Math.sin(pi*i/sides));
			}
		}
		
		centerOfMass.x = centerOfMass.y = 0;
		momentOfInertia = (0.5f)*(mass * r * r);
		this.width = r;
		this.color = color;
		TG.addChild(createShape(r, color, sides));
	}
	
	public Polygon(int type, int sides, float mass, float positionX, float positionY, 
			float velocityX, float velocityY, float orientation, 
			float angularVelocity, float extwidth, float ratio, Color3f color, int generation)
	{
		this(type, sides, mass, positionX, positionY, velocityX, velocityY, orientation, angularVelocity, extwidth, ratio, color);
		my_generation = generation;
	}
	
	public Polygon(int type, int vertices, float mass, Tuple2f position, Tuple2f velocity, float orientation, float angularVelocity, float extwidth, float ratio, Color3f color) {
		this(type, vertices, mass, position.x, position.y, velocity.x, velocity.y, orientation, angularVelocity, extwidth, ratio, color);
	}
	
	public int getGeneration() {
		return my_generation;
	}
	
	@Override
	public void clearCaches() {
		vertexCache = null;
		normalCache = null;
	}

	public Vector2f[] getVertices() {
		if (vertexCache == null) {
			vertexCache = new Vector2f[vertices.length / 2];
			for (int i = 0; i < vertices.length; i += 2) {
				float tmpX = vertices[i] * width/(10*ratio); //DIVIDE
				float tmpY = vertices[i+1] * width/(10*ratio); //THESE
				vertexCache[i/2] = new Vector2f();
				vertexCache[i/2].x = (float)(Math.cos(orientation) * tmpX - Math.sin(orientation) * tmpY) + position.x;
				vertexCache[i/2].y = (float)(Math.sin(orientation) * tmpX + Math.cos(orientation) * tmpY) + position.y;
			}
		}
		return vertexCache;
	}
	
	public Vector2f[] getNormals() {
		if (normalCache == null) {
			Vector2f[] vertices = getVertices();
			normalCache = new Vector2f[vertices.length];

			for (int i = 0; i < vertices.length; i++) {
				normalCache[i] = new Vector2f();
				normalCache[i].scaleAdd(-1, vertices[i], vertices[(i+1)%vertices.length]);
				normalCache[i].normalize();
				float tmp = normalCache[i].x;
				normalCache[i].x = normalCache[i].y;
				normalCache[i].y = -tmp;
			}
		}
		return normalCache;
	}
	
	public Vector2f getForward() {
		return new Vector2f(1f * (float)Math.cos(orientation), 1f * (float)Math.sin(orientation));
	}
	
	private Node createShape(float width, Color3f color, int sides) {
		IndexedTriangleArray geometry = 
				new IndexedTriangleArray(sides, GeometryArray.COORDINATES, 3*(sides-2));
		
		Point3f[] triVerts = new Point3f[sides];
		for (int i = 0; i < sides; i++)
			triVerts[i] = new Point3f(vertices[2*i], vertices[2*i+1], 0f);
		
		int[] triIndices = new int[3*(sides-2)];
		int triIndex = 0;
		for (int i = 1; i < sides-2+1; i++) {
			triIndices[triIndex++] = 0;
			triIndices[triIndex++] = i;
			triIndices[triIndex++] = i+1;
		}
		
		geometry.setCoordinates(0, triVerts);
		geometry.setCoordinateIndices(0, triIndices);
		
		//PointArray centerOfMassGeometry = new PointArray(1, GeometryArray.COORDINATES);
		//centerOfMassGeometry.setCoordinate(0, new Point3f(centerOfMass.x, centerOfMass.y, 0));
		
		BranchGroup root = new BranchGroup();
		if (color == null)
			color = new Color3f(0.5f,0.5f,0.5f);
			//color = new Color3f(Color.getHSBColor((float)Math.random(), 1, 1));
		Appearance appearance = new Appearance();
		appearance.setColoringAttributes(new ColoringAttributes(color, ColoringAttributes.FASTEST));
		PolygonAttributes polyAttr = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0);
		appearance.setPolygonAttributes(polyAttr);
		root.addChild(new Shape3D(geometry, appearance));
		
		appearance = new Appearance();
		appearance.setPointAttributes(new PointAttributes(4, true));
		//root.addChild(new Shape3D(centerOfMassGeometry, appearance));
	
		return root;
	}
	
	public static Polygon getRandomAsteroid(float extWidth, float speed) {
		float px = ((float)Math.random() - 0.5f)* 2f * extWidth;
		float py = ((float)Math.random() - 0.5f)* 2f * extWidth;

		return getRandomAsteroid(extWidth, speed, px, py);
	}
	
	public static Polygon getRandomAsteroid(float extWidth, float speed, 
			float positionX, float positionY)
	{
		int sides = MAX_SIDES;
		float mass = DEFAULT_MASS;
		float vx = ((float)Math.random() - 0.5f) * speed;
		float vy = ((float)Math.random() - 0.5f) * speed;
		float or = ((float)Math.PI)/(float)Math.random();
		float av = ((float)Math.random() - 0.5f) * 2f;
		
		Color3f c;
		double color_pick = Math.random();
		if(color_pick < 0.25)
			c = ASTEROID_COLOR1;
		else if(color_pick >= 0.25 && color_pick < 0.5)
			c = ASTEROID_COLOR2;
		else if(color_pick >= 0.5 && color_pick < 0.75)
			c = ASTEROID_COLOR3;
		else
			c = ASTEROID_COLOR4;
		
		return new Polygon(1, sides,mass,positionX,positionY,vx,vy,or,av,extWidth,DEFAULT_RATIO,c,1);
	}
}
